﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Beacon.SPC
{
    /// <summary>
    /// 14 or more consecutive points alternate in direction.
    /// </summary>
    public class Oscillation : ISpcRule
    {
        #region Members
        private const int PointCount = 14;

        SpcControlLimit _limit = null;
        SpcDataQueue _queue = new SpcDataQueue(PointCount);

        #endregion

        #region Constructor
        public Oscillation(SpcControlLimit limit)
        {
            _limit = limit;
        }
        #endregion

        #region ISpcRule Members

        /// <summary>
        /// return rule type
        /// </summary>
        /// <returns></returns>
        public SpcRules RuleType()
        {
            return SpcRules.Oscillation;
        }

        /// <summary>
        /// return rule point count
        /// </summary>
        /// <returns></returns>
        public int GetRulePointCount()
        {
            return PointCount;
        }

        /// <summary>
        /// add point
        /// </summary>
        /// <param name="data" type="double"></param>
        /// <returns> true if data is violated the rule, others false</returns>
        public bool AddPoint(double data)
        {
            _queue.Enqueue(data);
            bool rlt = violate();
            if (rlt)
                Reset();

            return rlt;
        }

        /// <summary>
        /// add point with sample size
        /// limits for data point will be calculated with sample size.
        /// </summary>
        /// <param name="data"></param>
        /// <param name="sampleSize"></param>
        /// <returns>true if data is violated the rule, others false</returns>
        public bool AddPoint(double data, double sampleSize)
        {
            _limit.Calculate((int)sampleSize);
            return AddPoint(data);
        }

        /// <summary>
        /// reset rule
        /// </summary>
        public void Reset()
        {
            _queue.Clear();
        }

        #endregion

        #region Private Functions

        /// <summary>
        /// travel through the queue to check.
        /// </summary>
        /// <returns></returns>
        private bool violate()
        {
            bool oscillation = true;

            double preFirstData = double.NaN;
            double preSecondData = double.NaN;

            if (_queue.Count < PointCount)
                return false;

            for (int i = 1; i < _queue.Count; i++)
            {
                if (i == 1)
                {
                    preFirstData = _queue.ElementAt(1);
                    preSecondData = _queue.ElementAt(0);
                }
                else
                {
                    double currData = _queue.ElementAt(i);

                    if (currData >= preFirstData && preFirstData>= preSecondData)
                        oscillation = false;
                    else if (currData <= preFirstData && preFirstData <= preSecondData)
                        oscillation = false;

                    if (!oscillation)
                        break;

                    preSecondData = preFirstData;
                    preFirstData = currData;
                    
                }
            }

            return oscillation;
        }

        #endregion
    }
}
